package com.ylr.send.framework.manager;

import com.alibaba.fastjson2.JSON;
import com.ylr.send.framework.service.SmsLogService;
import com.ylr.send.framework.service.SmsService;
import com.ylr.send.framework.service.SmsTemplateService;
import com.ylr.base.common.constant.Constant;
import com.ylr.base.common.constant.RegexConstant;
import com.ylr.base.common.enums.AesEnum;
import com.ylr.base.common.enums.ChannelEnum;
import com.ylr.base.common.enums.CommonEnum;
import com.ylr.base.common.enums.ResultEnum;
import com.ylr.base.common.exception.YlrException;
import com.ylr.base.common.po.user.UserPo;
import com.ylr.base.common.utils.DataUtils;
import com.ylr.base.common.utils.HttpUtils;
import com.ylr.base.common.utils.UserUtils;
import com.ylr.base.framework.service.AsyncService;
import com.ylr.basic.framework.resolver.YbAesResolver;
import com.ylr.send.common.dto.SendSmsDto;
import com.ylr.send.common.enums.SendResultEnum;
import com.ylr.send.common.enums.SmsChannelEnum;
import com.ylr.send.common.enums.SmsEnum;
import com.ylr.send.common.vo.BatchSendSmsVo;
import com.ylr.send.common.vo.SendSmsVo;
import com.ylr.send.framework.entity.SmsTemplateEntity;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-06-14 14:20:41
 * className: SmsManager
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class SmsManager {

    private static final Logger log = LoggerFactory.getLogger(SmsManager.class);

    /**
     * 短信渠道映射
     * key：  SmsChannelEnum类枚举值
     * value：SmsService子类
     */
    private static final Map<Integer, SmsService> map = new HashMap<>();

    private final SmsTemplateService smsTemplateService;

    private final SmsLogService smsLogService;

    private final YbAesResolver ybAesResolver;

    private final AsyncService asyncService;

    /**
     * 注册短信实现类
     * @param channel    短信渠道
     * @param smsService 短信服务对象
     */
    public static void register(Integer channel, SmsService smsService) {
        map.put(channel, smsService);
    }

    /**
     * 发送短信操作
     * @param sendSmsVo 参数对象
     * @return 发送结果
     */
    public SendSmsDto sendSms(SendSmsVo sendSmsVo) {
        // 获取请求request
        HttpServletRequest request = HttpUtils.getHttpServletRequest();

        String mobile;
        if (AesEnum.PLAIN.getValue().equals(sendSmsVo.getMobileType())) {
            mobile = sendSmsVo.getMobile();
        } else {
            // 手机号解密
            mobile = ybAesResolver.decode(sendSmsVo.getMobile(), sendSmsVo.getMobileType());
        }
        if (!Pattern.matches(RegexConstant.PHONE_REGEX, mobile)) {
            log.error("手机号格式错误。mobile={}", mobile);
            throw new YlrException(ResultEnum.MOBILE_FAIL);
        }

        // 1、获取短信模板
        SmsTemplateEntity smsTemplate = smsTemplateService.getSmsTemplateByCode(sendSmsVo.getCode());

        // 2、获取短信渠道服务
        SmsService smsService = this.getSmsService(smsTemplate.getChannel());

        SendSmsDto sendSmsDto = null;
        try {
            // 3、校验短信参数
            smsService.validParamMap(smsTemplate.getParams(), sendSmsVo.getParamMap());

            // 4、发送短信
            sendSmsDto = smsService.sendSms(mobile, smsTemplate, sendSmsVo.getParamMap());

            return sendSmsDto;
        } finally {
            SendSmsDto _sendSmsDto = sendSmsDto;

            // 5、添加短信发送日志
            asyncService.runAsync(() -> {
                String _mobile = mobile;
                String subMobile = DataUtils.dataMask(mobile);
                if (AesEnum.PLAIN.getValue().equals(sendSmsVo.getMobileType())) {
                    // 参数携带明文手机号，需要加密存储
                    _mobile = ybAesResolver.encrypt(sendSmsVo.getMobile(), AesEnum.HEX);
                }

                Integer channel = Optional.ofNullable(request.getHeader(Constant.CHANNEL))
                        .map(ChannelEnum::getChannelEnum)
                        .map(ChannelEnum::getValue)
                        .orElse(Constant.NEGATIVE_ONE);
                Integer module = Optional.ofNullable(request.getHeader(Constant.SOURCE))
                        .map(ChannelEnum::getChannelEnum)
                        .map(ChannelEnum::getValue)
                        .orElse(Constant.NEGATIVE_ONE);
                // 参数序列化
                String param = Optional.ofNullable(sendSmsVo.getParamMap())
                        .map(JSON::toJSONString)
                        .map(ybAesResolver::encryptToHex)
                        .orElse(StringUtils.EMPTY);

                // 发送结果
                String result = StringUtils.EMPTY;
                Integer status = SmsEnum.SEND_FAIL.getValue();
                String remark = StringUtils.EMPTY;
                if (Objects.nonNull(_sendSmsDto)) {
                    if (!CollectionUtils.isEmpty(_sendSmsDto.getResultMap())) {
                        result = JSON.toJSONString(_sendSmsDto.getResultMap());
                        result = ybAesResolver.encryptToHex(result);
                    }
                    status = _sendSmsDto.getStatus();
                    if (SmsEnum.SEND_FAIL.getValue().equals(status)) {
                        // 发送失败，把失败描述放到描述中，可以直接查看
                        remark = _sendSmsDto.getMsg();
                    }
                }

                String createUser = StringUtils.EMPTY;
                Long createUserId = CommonEnum.DEFAULT_ID.getLongValue();
                UserPo userPo = UserUtils.getUser();
                if (Objects.nonNull(userPo)) {
                    createUser = userPo.getUsername();
                    createUserId = userPo.getId();
                }
                // 保存短信发送记录
                smsLogService.saveSmsLog(smsTemplate.getId(), smsTemplate.getVersion() , _mobile, subMobile, channel,
                        module, param, result, status, createUser, createUserId, remark);
            });
        }

    }

    public SendSmsDto batchSendSms(BatchSendSmsVo batchSendSmsVo) {
        // 获取请求request
        HttpServletRequest request = HttpUtils.getHttpServletRequest();

        List<String> mobileList = new ArrayList<>();
        // 判断接受手机号是否明文
        boolean isPlain = AesEnum.PLAIN.getValue().equals(batchSendSmsVo.getMobileType());
        if (isPlain) {
            mobileList.addAll(batchSendSmsVo.getMobileList());
        } else {
            for (String mobile : batchSendSmsVo.getMobileList()) {
                // 手机号解密
                mobile = ybAesResolver.decode(mobile, batchSendSmsVo.getMobileType());

                mobileList.add(mobile);
            }
        }
        String errorMobile = mobileList.stream()
                .filter(mobile -> !Pattern.matches(RegexConstant.PHONE_REGEX, mobile))
                .findFirst()
                .orElse(null);
        if (Objects.nonNull(errorMobile)) {
            log.error("手机号格式错误。mobile={}", errorMobile);
            throw new YlrException(ResultEnum.MOBILE_FAIL);
        }

        // 1、获取短信模板
        SmsTemplateEntity smsTemplate = smsTemplateService.getSmsTemplateByCode(batchSendSmsVo.getCode());

        // 2、获取短信渠道服务
        SmsService smsService = this.getSmsService(smsTemplate.getChannel());

        SendSmsDto sendSmsDto = null;
        try {
            // 3、校验短信参数
            smsService.validParamMap(smsTemplate.getParams(), batchSendSmsVo.getParamMap());

            // 4、发送短信
            sendSmsDto = smsService.batchSendSms(mobileList, smsTemplate, batchSendSmsVo.getParamMap());

            return sendSmsDto;
        } finally {
            SendSmsDto _sendSmsDto = sendSmsDto;

            // 5、添加短信发送日志
            asyncService.runAsync(() -> {
                int length = batchSendSmsVo.getMobileList().size();
                List<String[]> _mobileList = new ArrayList<>(length);
                for (int i = 0; i < length; i++) {
                    String subMobile;
                    String mobile = batchSendSmsVo.getMobileList().get(i);
                    if (isPlain) {
                        // 脱敏
                        subMobile = DataUtils.dataMask(mobile);
                        // 加密
                        mobile = ybAesResolver.encrypt(mobile, AesEnum.HEX);
                    } else {
                        // 脱敏
                        subMobile = DataUtils.dataMask(mobileList.get(i));
                    }
                    _mobileList.add(new String[] { mobile,  subMobile });
                }


                Integer channel = Optional.ofNullable(request.getHeader(Constant.CHANNEL))
                        .map(ChannelEnum::getChannelEnum)
                        .map(ChannelEnum::getValue)
                        .orElse(Constant.NEGATIVE_ONE);
                Integer module = Optional.ofNullable(request.getHeader(Constant.SOURCE))
                        .map(ChannelEnum::getChannelEnum)
                        .map(ChannelEnum::getValue)
                        .orElse(Constant.NEGATIVE_ONE);
                // 参数序列化
                String param = Optional.ofNullable(batchSendSmsVo.getParamMap())
                        .map(JSON::toJSONString)
                        .map(ybAesResolver::encryptToHex)
                        .orElse(StringUtils.EMPTY);

                // 发送结果
                String result = StringUtils.EMPTY;
                Integer status = SmsEnum.SEND_FAIL.getValue();
                String remark = StringUtils.EMPTY;
                if (Objects.nonNull(_sendSmsDto)) {
                    if (!CollectionUtils.isEmpty(_sendSmsDto.getResultMap())) {
                        result = JSON.toJSONString(_sendSmsDto.getResultMap());
                        result = ybAesResolver.encryptToHex(result);
                    }
                    status = _sendSmsDto.getStatus();
                    if (SmsEnum.SEND_FAIL.getValue().equals(status)) {
                        remark = _sendSmsDto.getMsg();
                    }
                }

                String createUser = StringUtils.EMPTY;
                Long createUserId = CommonEnum.DEFAULT_ID.getLongValue();
                UserPo userPo = UserUtils.getUser();
                if (Objects.nonNull(userPo)) {
                    createUser = userPo.getUsername();
                    createUserId = userPo.getId();
                }
                // 保存短信发送记录
                smsLogService.batchSaveSmsLog(smsTemplate.getId(), smsTemplate.getVersion() , _mobileList, channel, module,
                        param, result, status, createUser, createUserId, remark);
            });
        }
    }

    /**
     * 构造短信发送内容
     * @param channel  短信渠道
     * @param content  短信模板
     * @param paramMap 参数映射
     * @return 完整短信内容
     */
    public String buildContent(Integer channel, String content, Map<String, String> paramMap, boolean highlight) {
        // 获取短信渠道服务
        SmsService smsService = this.getSmsService(channel);

        // 添加短信渠道自有的参数
        paramMap = smsService.addChannelParam(paramMap);

        // 构造
        return smsService.buildContent(content, paramMap, highlight);
    }

    /**
     * 获取短信渠道自有的参数操作
     * @param channel 短信渠道
     * @return 短信参数映射
     */
    public Map<String, String> getChannelParam(Integer channel) {
        // 获取短信渠道服务
        SmsService smsService = this.getSmsService(channel);
        // 获取短信渠道自有的参数
        return smsService.getChannelParam();
    }

    /**
     * 获取短信渠道服务
     * @param channel 短信渠道
     * @return 短信渠道服务对象
     */
    private SmsService getSmsService(Integer channel) {
        // 获取短信渠道服务
        SmsService smsService = map.get(channel);
        if (Objects.isNull(smsService)) {
            log.warn("短信模板对应的短信渠道不存在。{}", SmsChannelEnum.getChannelEnum(channel));
            throw new YlrException(SendResultEnum.NOT_CHANNEL_FAIL);
        }
        return smsService;
    }
}
